package com.sudo.controller;

import com.sudo.aspect.AuthorizationApi;
import com.sudo.common.enums.SysStatus;
import com.sudo.common.enums.UserParams;
import com.sudo.common.utils.*;
import com.sudo.pojo.SysRole;
import com.sudo.pojo.SysUser;
import com.sudo.pojo.bo.SimpleUserBO;
import com.sudo.pojo.bo.SysUserBasicInfoBO;
import com.sudo.pojo.vo.SysSimpleUserVO;
import com.sudo.pojo.vo.SysUserReVO;
import com.sudo.pojo.vo.SysUserTokenVO;
import com.sudo.service.SysRoleService;
import com.sudo.service.SysUserLoginRecordService;
import com.sudo.service.SysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.UUID;
import java.util.concurrent.ExecutorService;

@Api(value = "用户接口",tags = {"用户相关的接口"})
@RestController
@RequestMapping("sysUser")
public class SysUserController extends BaseController {

    private final static Logger logger = LoggerFactory.getLogger(SysUserController.class);

    @Autowired
    private RedisOperator redisOperator;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private SysUserLoginRecordService sysUserLoginRecordService;

    /**
     * 用户登录
     * @param mailOrUsername 账户
     * @param pwd 密码
     * @param request req
     * @param response resp
     * @return JsonRes
     */
    @ApiOperation(value="用户登录",notes="采用用户名或邮箱登录", httpMethod = "POST")
    @PostMapping("userLogin")
    public JsonRes userLogin(@RequestParam String mailOrUsername,
                             @RequestParam String pwd,
                             HttpServletRequest request,
                             HttpServletResponse response) {
        if (StringUtils.isBlank(mailOrUsername)) {
            logger.warn("账号不能为空");
            return JsonRes.errorMsg("账号不能为空");
        }
        if (StringUtils.isBlank(pwd)) {
            logger.warn("密码不能为空");
            return JsonRes.errorMsg("密码不能为空");
        }

        //判断账户是否存在
        boolean isExist = sysUserService.queryMailOrUsernameIsExist(mailOrUsername);
        if (!isExist) {
            logger.warn("账户不存在");
            return JsonRes.errorMsg("账户不存在");
        }
        //如果账户存在，则登录验证
        SysUser sysUser = sysUserService.sysUserLoginByMailOrUsername(mailOrUsername, pwd);
        if (null == sysUser) {
            logger.warn("登录失败，请检查密码是否正确");
            return JsonRes.errorMsg("登录失败，请检查密码是否正确");
        } else if (SysStatus.OFF.value.equals(sysUser.getStatus())) {
            logger.warn("登录失败，该用户已被禁止登陆");
            return JsonRes.errorMsg("登录失败，该用户已被禁止登陆");
        }
        //如果角色被禁止不能登录
        SysRole sysRole = sysRoleService.getRoleByUsername(sysUser.getUsername());
        if (SysStatus.OFF.value.equals(sysRole.getStatus())) {
            logger.warn("登录失败，该角色已被禁止登陆");
            return JsonRes.errorMsg("登录失败，该角色已被禁止登陆");
        }

        SysUserTokenVO sysUserVO = new SysUserTokenVO();
        BeanUtils.copyProperties(sysUser,sysUserVO);

        //实现用户的redis会话
        String uniqueToken = UUID.randomUUID().toString().trim();
        redisOperator.set(UserParams.REDIS_USER_TOKEN.value +":"+sysUser.getUsername(),
                uniqueToken,7200);

        sysUserVO.setUniqueToken(uniqueToken);
        //设置cookie
        CookieUtils.setCookie(request,response,"user",
                JsonUtils.objectToJson(sysUserVO),true);
        addUserLoginInfoThread(sysUser.getUsername(), request);
        logger.info("用户登录成功");
        return JsonRes.ok(sysUserVO);
    }

    @ApiOperation(value = "判断用户token是否正常",notes = "判断用户token是否正常",httpMethod = "GET")
    @PostMapping("/isUserTokenRight")
    public JsonRes isUserTokenRight(HttpServletRequest request) {
        String username = getSessionUser(request);
        String userToken = request.getHeader(UserParams.HEADER_USER_TOKEN.value);
        String redisToken = redisOperator.get(UserParams.REDIS_USER_TOKEN.value + ":" + username);
        if (userToken.equals(redisToken)) {
            return JsonRes.ok();
        }
        return JsonRes.errorMsg("无用户登录信息");
    }


    @ApiOperation(value = "用户退出登录",notes = "用户退出登录，清除会话和cookie",httpMethod = "POST")
    @PostMapping("/logout")
    public JsonRes logout(@RequestParam String username,
                          HttpServletRequest request,
                          HttpServletResponse response) {
        //清除用户相关的cookie信息
        CookieUtils.deleteCookie(request, response, "user");
        //用户退出登录，清除redis中user的回话信息
        redisOperator.del(UserParams.REDIS_USER_TOKEN.value + ":" + username);
        return JsonRes.ok();
    }


    @AuthorizationApi(menu = "userRun",button = "search")
    @ApiOperation(value = "分页查询所有用户核心信息",notes = "分页查询所有用户核心信息，进行管理",httpMethod = "GET")
    @GetMapping("/queryAllSysUserMainInfoByPage")
    public JsonRes queryAllSysUserMainInfoByPage(@RequestParam String usernameOrNick,
                                         @RequestParam Integer page,
                                         @RequestParam Integer pageSize) {
        PagedGridResult pagedGridResult = sysUserService.queryAllSysUserMainInfoByPage(page, pageSize, usernameOrNick);
        return JsonRes.ok(pagedGridResult);
    }

    @AuthorizationApi(menu = "userRun",button = "search_detail")
    @ApiOperation(value = "根据username查询用户详情和角色code、Name",notes = "根据username查询用户部分信息和角色code、Name，进行修改",httpMethod = "GET")
    @GetMapping("getSysUserAndRoleByUsername")
    public JsonRes getSysUserAndRoleByUsername(@RequestParam String username) {
        SysUserReVO sysUserReVO = sysUserService.getSysUserAndRoleByUsername(username);
        return JsonRes.ok(sysUserReVO);
    }


    @AuthorizationApi(menu = "userRun",button = "add")
    @ApiOperation(value = "添加用户（包括角色关联关系）",notes = "添加用户（包括角色关联关系）",httpMethod = "POST")
    @PostMapping("addUser")
    public JsonRes addUser(@RequestBody @Valid SimpleUserBO simpleUserBO,
                            BindingResult result,
                           HttpServletRequest request) {
        if (result.hasErrors()) {
            return JsonRes.errorMsg(getFirstError(result));
        }

        //1.不允许添加超级管理员
        if (superAdmin(simpleUserBO.getRoleCode())) {
            return JsonRes.errorMsg("禁止添加超级管理员");
        }
        //2.判断username是否已存在
        SysUser sysUser = sysUserService.getSysUserByUsername(simpleUserBO.getUsername());
        if (null != sysUser) {
            return JsonRes.errorMsg("该账号已存在");
        }
        String sessionUser = getSessionUser(request);

        //3.判断角色是否存在
        boolean isHas = sysRoleService.hasRoleCode(simpleUserBO.getRoleCode());
        if (!isHas) {
            return JsonRes.errorMsg("当前角色不存在");
        }
        int affectCount = sysUserService.addUser(simpleUserBO,sessionUser);
        return JsonRes.ok(affectCount);
    }

    @AuthorizationApi(menu = "userRun",button = "update_role_status")
    @ApiOperation(value = "切换用户的角色或状态",notes = "切换用户的角色或状态",httpMethod = "POST")
    @PostMapping("updateSysUserRoleStatus")
    public JsonRes updateSysUserRoleStatus(@RequestParam("username") String username,
                                     @RequestParam("roleCode") String roleCode,
                                     @RequestParam("status") String status,
                           HttpServletRequest request) {
        String sessionUser = getSessionUser(request);
        //1.只允许超级管理员操作
        if (!superName(sessionUser)) {
            return JsonRes.errorMsg("只允许超级管理员操作");
        }
        //2.不允许修改超级管理员
        if (superName(username)) {
            return JsonRes.errorMsg("不允许修改超级管理员账号");
        }
        //3.不允许切换为超级管理员
        if (superAdmin(roleCode)) {
            return JsonRes.errorMsg("不允许切换为超级管理员");
        }
        boolean isHas = sysRoleService.hasRoleCode(roleCode);
        if (!isHas) {
            return JsonRes.errorMsg("该角色不存在");
        }
        int affectCount = sysUserService.updateSysUserRoleStatus(username, roleCode, status);
        return JsonRes.ok(affectCount);
    }

    @AuthorizationApi(menu = "userRun",button = "delete")
    @ApiOperation(value = "根据username删除用户",notes = "根据username删除用户",httpMethod = "POST")
    @PostMapping("deleteSysUserByUsername")
    public JsonRes deleteSysUserByUsername(@RequestParam("username") String username,
                                           HttpServletRequest request) {
        String sessionUser = getSessionUser(request);
        //1.只允许超级用户操作
        if (!superName(sessionUser)) {
            return JsonRes.errorMsg("只允许超级管理员操作");
        }
        //2.不允许删除超级用户
        if (superName(username)) {
            return JsonRes.errorMsg("不允许删除超级用户");
        }
        int affectCount = sysUserService.deleteSysUserByUsername(username);
        return JsonRes.ok(affectCount);
    }

    @AuthorizationApi(menu = "user_online",button = "search")
    @ApiOperation(value = "分页获取所有在线用户",notes = "分页获取所有在线用户",httpMethod = "GET")
    @GetMapping("getOnlineUserByPage")
    public JsonRes getOnlineUserByPage(@RequestParam("page") Integer page,
                                       @RequestParam("pageSize") Integer pageSize) {

        PagedGridResult pagedGridResult = sysUserService.getOnlineUserByPage(page ,pageSize);
        return JsonRes.ok(pagedGridResult);
    }

    @AuthorizationApi(menu = "user_online",button = "shotOff")
    @ApiOperation(value = "踢出在线用户",notes = "踢出在线用户",httpMethod = "POST")
    @PostMapping("shotOffOnlineUser")
    public JsonRes shotOffOnlineUser(@RequestParam("username") String username) {
        if (superName(username)) {
            return JsonRes.errorMsg("禁止踢出超级管理员");
        }
        redisOperator.del(UserParams.REDIS_USER_TOKEN.value+":"+username);
        return JsonRes.ok();
    }

    private void addUserLoginInfoThread(String username ,HttpServletRequest request) {
        ExecutorService executor = ThreadPoolHelper.getSingleThread();
        executor.execute(() -> sysUserLoginRecordService.addUserLoginRecord(username, request));
        try {
            ThreadPoolHelper.endThread(executor);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @ApiOperation(value = "获取我的用户资料",notes = "获取我的用户资料",httpMethod = "GET")
    @GetMapping("getMyUserInfo")
    public JsonRes getMyUserInfo(HttpServletRequest request) {
        String sessionUser = getSessionUser(request);
        SysUser sysUser = sysUserService.getSysUserByUsername(sessionUser);
        return JsonRes.ok(sysUser);
    }

    @ApiOperation(value = "获取我的简单资料",notes = "获取我的简单资料",httpMethod = "GET")
    @GetMapping("getMySimpleUserInfo")
    public JsonRes getMySimpleUserInfo(HttpServletRequest request) {
        String sessionUser = getSessionUser(request);
        SysSimpleUserVO sysSimpleUserVO = sysUserService.getMySimpleUserInfo(sessionUser);
        return JsonRes.ok(sysSimpleUserVO);
    }

    @ApiOperation(value = "修改个人资料", notes = "修改个人资料", httpMethod = "GET")
    @PostMapping("updateMyUserInfo")
    public JsonRes updateMyUserInfo(@RequestBody @Valid SysUserBasicInfoBO basicInfoBO,
                                    BindingResult result,
                                    HttpServletRequest request) {
        if (result.hasErrors()) {
            return JsonRes.errorMsg(getFirstError(result));
        }
        String sessionUser = getSessionUser(request);
        if (!sessionUser.equals(basicInfoBO.getUsername())) {
            return JsonRes.errorMsg("禁止修改他人资料");
        }
        int affectCount = sysUserService.updateMyUserInfo(basicInfoBO);
        return JsonRes.ok(affectCount);
    }
}
